package com.gx.aop;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.alibaba.fastjson.JSONObject;
import com.gx.util.JdkVersionUtil;

@Component
@Aspect
public class LogInterceptor {
	@Resource
	private HttpServletRequest request;
	private boolean IsDev = true;

	public Log log = LogFactory.getLog(LogInterceptor.class);

	@Pointcut("execution(public * com.gx.web.*.*(..))")
	public void log() {
		log.info(request.getParameterMap());
	}

	@AfterReturning(pointcut = "log()", returning = "returnValue")
	public void afterReturning(JoinPoint joinPoint, Object returnValue) {

		if (IsDev) {
			devEnvironmentLog(joinPoint, returnValue);
		} else {
			productEnvironmentLog(joinPoint, returnValue);
		}
	}

	private void devEnvironmentLog(JoinPoint joinPoint, Object returnValue) {
		StringBuilder sb = new StringBuilder("\nSpringMVC action report -------- ").append(
				new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append(
				" ------------------------------\n");
		sb.append(getController(joinPoint));
		sb.append(getMethod(joinPoint));
		sb.append(getUri());
		sb.append(getParameter(joinPoint));
		sb.append("RemoteAddr  : " + getIpAddr(request) + "\n");
		sb.append(getReturn(returnValue));
		sb.append("--------------------------------------------------------------------------------\n");
		System.out.print(sb.toString());
	}

	private void productEnvironmentLog(JoinPoint joinPoint, Object returnValue) {
		StringBuilder sb = new StringBuilder();

		sb.append(request.getRequestURI()).append(", ");
		sb.append("IP: " + getIpAddr(request)).append(", [");

		Map<String, String[]> parameters = request.getParameterMap();

		for (Map.Entry<String, String[]> entity : parameters.entrySet()) {

			sb.append(String.format("%s = %s, ", entity.getKey(), StringUtils.join(entity.getValue(), ',')));
		}

		sb.delete(sb.length() - 2, sb.length()).append("]");

		log.info(sb.toString());
	}

	private Map<String, MultipartFile> getRequestFileMap(JoinPoint joinPoint) {
		Map<String, MultipartFile> fileMap = null;
		if (JdkVersionUtil.isJava8()) {
			Object[] args = joinPoint.getArgs();
			for (Object object : args) {
				if (object instanceof MultipartHttpServletRequest) {
					MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) object;
					fileMap = multipartHttpServletRequest.getFileMap();
					break;
				}
			}
		}
		return fileMap;
	}

	private String getController(JoinPoint joinPoint) {
		return new StringBuffer().append("Controller  : ").append(joinPoint.getTarget().getClass().getName())
				.append(".(").append(joinPoint.getTarget().getClass().getSimpleName()).append(".java:1)").toString();
	}

	private String getMethod(JoinPoint joinPoint) {
		return new StringBuffer().append("\nMethod      : ").append(joinPoint.getSignature().getName()).append("\n")
				.toString();
	}

	private String getUri() {
		String uri = request.getRequestURI();
		if (uri != null) {
			return new StringBuffer().append("url         : ").append(uri).append(" user=" + request.getRemoteUser())
					.append("\n").toString();
		}
		return "";
	}

	private String getParameter(JoinPoint joinPoint) {
		StringBuffer sb = new StringBuffer();
		Map<String, MultipartFile> fileMap = getRequestFileMap(joinPoint);
		Enumeration<String> e = request.getParameterNames();
		if (e.hasMoreElements() || (fileMap != null && fileMap.size() > 0)) {
			sb.append("Parameter   : ");
			while (e.hasMoreElements()) {
				String name = e.nextElement();
				String[] values = request.getParameterValues(name);
				if (values.length == 1) {
					sb.append(name).append("=").append(values[0]);
				} else {
					sb.append(name).append("[]={");
					for (int i = 0; i < values.length; i++) {
						if (i > 0)
							sb.append(",");
						sb.append(values[i]);
					}
					sb.append("}");
				}
				sb.append("  ");
			}
			if (fileMap != null && fileMap.size() > 0) {
				for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
					MultipartFile file = entry.getValue();
					sb.append(entry.getKey()).append("=").append(file.getOriginalFilename());
					sb.append(" (contentType=" + file.getContentType() + ",size=" + file.getSize() + ")");
					sb.append("  ");
				}
			}
			sb.append("\n");
		}
		return sb.toString();
	}

	private String getReturn(Object returnValue) {
		StringBuffer sb = new StringBuffer();
		String returnJSON = "";
		returnJSON = JSONObject.toJSONString(returnValue);
		long l=returnJSON.length();
		if (l<Integer.MAX_VALUE) {
			if (l>3000) {//对于大于3000的（一般是文件）进行截断处理  取前50和后300
				String strTempS=returnJSON.substring(0,50)
						+"......(过长省略)\n              "
						+returnJSON.substring((int) (l-300));
				returnJSON=strTempS;
			}
		}else {
			returnJSON=returnJSON.substring(0,100)+"......(过长省略)";
		}
		sb.append("return      : " + returnJSON);
		sb.append("\n");
		String str=sb.toString();
		str=str.replace("\\\"", "\"");
		str=str.replace("\"{", "{");
		str=str.replace("\"}", "}");
		return str;
	}

	private String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		if (ip.equals("0:0:0:0:0:0:0:1")) {
			ip = "127.0.0.1";
		}
		return ip;
	}

}
